﻿using SHTools;
using System;
using System.Collections;
using System.Collections.Generic;
// 引入Unity编辑器命名空间，仅在Unity编辑器环境下生效
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

[ExecuteInEditMode]
public class LchDayNightSystem : MonoBehaviour
{
    // 将所有材质属性ID提前定义
    static int _ZTest = Shader.PropertyToID("_ZTest");
    static int _SunAngle = Shader.PropertyToID("_SunAngle");
    static int _SunAlpha = Shader.PropertyToID("_SunAlpha");

    static int _FogStar = Shader.PropertyToID("_FogStar");
    static int _FogThickness = Shader.PropertyToID("_FogThickness");

 

    // 存储Volume组件的引用
    public Volume volume;
    // 存储Bloom效果的引用
    private Bloom bloom;

    // 天空球雾相关设置的标题
    [Header("天空球雾")]
    // 天空盒材质
    public Material skyboxMaterial;
    // 是否使用自定义天空雾效果
    public bool customSkyFog = false;


    [Header("体积光")]
    public bool godRay = false;

    // 主平行光
    public Light mainDirLight;

    // 主光颜色
    public Color mainLightColor = new Color(1f, 0.9568627f, 0.8392157f, 1.0f);

    public float mainLightIntensity = 1.0f;
    // 自定义标签，显示为“太阳角度”，并限制取值范围在5到35之间
    [Label("太阳角度")]
    [Range(5, 35)]
    public float sunAngle = 30;

    // 太阳绕Y轴的角度
    public float sunAngleY = 200;
    //太阳可见性
    public float sunAlpha = 1.0f;

    [HideInInspector]
    [Label("雾开始距离")]
    [Range(1, 1000)]
    public float fogStar = 50;


    [HideInInspector]
    [Label("雾厚度")]
    [Range(1, 1000)]
    public float fogThickness = 100;
    

    // 是否启用昼夜数据
    public bool enableDataNight = true;
    // 自定义标签，显示为“昼夜时间”，并且根据enableDataNight的值决定是否显示，取值范围在0到24之间
    [Label("昼夜时间", "enableDataNight")]
    [Range(0, 24)]
    public float dataTime = 0;

    [CNEnum(typeof(AmbientType), "环境色类型")]
    // 环境色类型
    public AmbientType ambientType = AmbientType.ThreeColor;

    // 昼夜变化数据的标题
    [Header("昼夜变化数据")]
    public DayNightCurve curve;
    // 
    [Label("昼夜时间流逝速度")]
    [Range(0, 0.33f)]
    public float dataSpeed = 0.0f;

    private void OnEnable()
    {
        if (null != volume)
        {
            volume.profile = Instantiate(volume.sharedProfile);
            volume.profile.TryGet(out bloom);
        }
    }

    // 当对象被销毁时调用
    private void OnDestroy()
    {
        // 启用雾效
        RenderSettings.fog = true;
        // 禁用天空雾效果的关键字
        if(skyboxMaterial)
            skyboxMaterial.DisableKeyword("SKY_FOG_EFFECT");
    }

    // 平滑过渡函数
    public static float Smoothstep(float edge0, float edge1, float x)
    {
        // 首先将 x 进行归一化处理，使其值在0到1之间
        float t = Mathf.Max(0, Mathf.Min(1, (x - edge0) / (edge1 - edge0)));
        // 应用 smoothstep 的多项式公式
        return t * t * (3 - 2 * t);
    }

    // 重新映射函数，将输入值从一个范围映射到另一个范围
    public static float Remap(float x, float inMin, float inMax, float outMin, float outMax)
    {
        // 先计算映射结果
        float result = outMin + (x - inMin) / (inMax - inMin) * (outMax - outMin);
        // 对结果进行范围限制，确保结果在输出范围内
        return Mathf.Max(outMin, Mathf.Min(result, outMax));
    }

    // 每帧更新函数
    void Update()
    {
        dataTime += dataSpeed * Time.deltaTime;
        dataTime %= 24f;

        godRay = QualitySettings.GetQualityLevel() > 1;
        // 获取当前的天空盒材质
        skyboxMaterial = RenderSettings.skybox;
        if(skyboxMaterial == null) return;
        if (enableDataNight && null != curve)
        {
            // 如果启用了昼夜数据
            var dayNightDatas = curve.dayNightDatas;
            int materialCount = dayNightDatas.Count;

            // 第一个昼夜数据的索引
            int index1 = 0;
            // 第二个昼夜数据的索引
            int index2 = 0;
            // 插值因子
            float t = -1f;
            // 遍历昼夜数据数组
            for (int i = 0; i < materialCount; i++)
            {
                // 如果当前昼夜数据的时间大于等于当前时间
                if (dayNightDatas[i].time >= dataTime)
                {
                    // 如果当前昼夜数据的时间等于当前时间
                    if (dayNightDatas[i].time == dataTime)
                    {
                        index1 = i;
                        index2 = i;
                        t = 0f;
                        break;
                    }
                    else
                    {
                        index2 = i;
                        // 如果是第一个数据
                        if (index2 == 0)
                        {
                            index1 = materialCount - 1;
                            float t1 = 24f - dayNightDatas[index1].time;
                            t = (dataTime + t1) / (dayNightDatas[index2].time + t1);
                        }
                        else
                        {
                            index1 = index2 - 1;
                            t = (dataTime - dayNightDatas[index1].time) / (dayNightDatas[index2].time - dayNightDatas[index1].time);
                        }
                        break;
                    }
                }
            }
            // 如果没有找到合适的插值因子
            if (t < 0f)
            {
                index1 = materialCount - 1;
                index2 = 0;
                t = (dataTime - dayNightDatas[index1].time) / (24f + dayNightDatas[index2].time - dayNightDatas[index1].time);
            }
            // 如果两个昼夜数据的材质都不为空
            if (null != dayNightDatas[index1].data.mat && null != dayNightDatas[index2].data.mat)
            {
                // 插值天空盒材质
                RenderSettings.skybox.Lerp(dayNightDatas[index1].data.mat, dayNightDatas[index2].data.mat, t);
                // 插值主光颜色
                mainLightColor = Color.Lerp(dayNightDatas[index1].data.mainLightColor, dayNightDatas[index2].data.mainLightColor, t);
                mainLightIntensity = Mathf.Lerp(dayNightDatas[index1].data.mainLightIntensity, dayNightDatas[index2].data.mainLightIntensity, t);
                // 插值太阳角度
                sunAngle = Mathf.Lerp(dayNightDatas[index1].sunAngle, dayNightDatas[index2].sunAngle, t);
                // 插值太阳绕Y轴的角度
                sunAngleY = Mathf.Lerp(dayNightDatas[index1].sunAngleY, dayNightDatas[index2].sunAngleY, t);

                sunAlpha = Mathf.Lerp(dayNightDatas[index1].sunAlpha, dayNightDatas[index2].sunAlpha, t);

                fogStar = Mathf.Lerp(dayNightDatas[index1].fogStar, dayNightDatas[index2].fogStar, t);
                fogThickness = Mathf.Lerp(dayNightDatas[index1].fogThickness, dayNightDatas[index2].fogThickness, t);
                // 如果环境色类型是三色
                if (ambientType == AmbientType.ThreeColor)
                {
                    // 设置环境光模式为三色
                    RenderSettings.ambientMode = AmbientMode.Trilight;
                    // 插值天空环境色
                    RenderSettings.ambientSkyColor = Color.Lerp(dayNightDatas[index1].data.topColor, dayNightDatas[index2].data.topColor, t);
                    // 插值赤道环境色
                    RenderSettings.ambientEquatorColor = Color.Lerp(dayNightDatas[index1].data.middleColor, dayNightDatas[index2].data.middleColor, t);
                    // 插值地面环境色
                    RenderSettings.ambientGroundColor = Color.Lerp(dayNightDatas[index1].data.bottomColor, dayNightDatas[index2].data.bottomColor, t);
                }
                else
                {
                    // 设置环境光模式为天空盒
                    RenderSettings.ambientMode = AmbientMode.Skybox;
                    // 插值环境光探针
                    RenderSettings.ambientProbe = dayNightDatas[index1].data.sh * (1 - t) + dayNightDatas[index2].data.sh * t;
                }

                if (null == bloom && null != volume)
                {
                    volume.profile.TryGet(out bloom);
                }
                if (bloom)
                {
                    float bloomInt = Mathf.Lerp(dayNightDatas[index1].data.bloomIntensity, dayNightDatas[index2].data.bloomIntensity, t);
                    bloom.intensity.value = bloomInt;
                    bloom.intensity.overrideState = true;
                }
               
                
            }
            skyboxMaterial.SetFloat(_FogStar, fogStar);
            skyboxMaterial.SetFloat(_FogThickness, fogThickness);
            //fogStar = Mathf.Lerp(dayNightDatas[index1].fogStar, dayNightDatas[index2].fogStar, t);
            //fogThickness = Mathf.Lerp(dayNightDatas[index1].fogThickness, dayNightDatas[index2].fogThickness, t);
#if UNITY_EDITOR
            // 这个unity编辑器界面逻辑，最终打包不会有这部分代码

            // 遍历昼夜数据数组
            for (int i = 0; i < dayNightDatas.Count; i++)
            {
                // 设置当前昼夜数据的环境色类型
                dayNightDatas[i].data.ambientType = ambientType;
                if (dayNightDatas[i].goToTime)
                {
                    dataTime = dayNightDatas[i].time;
                    var n = dayNightDatas[i];
                    n.goToTime = false;
                    dayNightDatas[i] = n;
                    EditorUtility.SetDirty(curve);
                    break;
                }
            }
#endif
        }

        // 如果使用自定义天空雾效果
        if (customSkyFog)
        {
            // 禁用全局雾效
            RenderSettings.fog = false;
            // 启用天空雾效果的关键字
            skyboxMaterial.EnableKeyword("SKY_FOG_EFFECT");
            // 设置Z测试值
            skyboxMaterial.SetFloat(_ZTest, 8);
            // 设置太阳角度
            skyboxMaterial.SetFloat(_SunAngle, sunAngle);
            skyboxMaterial.SetFloat(_SunAlpha, sunAlpha);
        }
        else
        {
            // 启用全局雾效
            RenderSettings.fog = true;
            // 禁用天空雾效果的关键字
            skyboxMaterial.DisableKeyword("SKY_FOG_EFFECT");
            // 设置Z测试值
            skyboxMaterial.SetFloat(_ZTest, 4);
        }
        if (godRay)
        {
            skyboxMaterial.EnableKeyword("GOD_RAY");
        }
        else
        {
            skyboxMaterial.DisableKeyword("GOD_RAY");
        }
        // 调用更新反射数据的函数
        //UpdateReflect();
        // 如果主平行光不为空
        if (null != mainDirLight)
        {
            // 设置主平行光的颜色
            mainDirLight.color = mainLightColor;
            mainDirLight.intensity = mainLightIntensity;


            // 重新映射太阳角度
            float angleX = Remap(sunAngle, 0f, 35f, 28f, 35f);
            // 先创建绕 X 轴旋转 angleX 度的四元数
            Quaternion rotationX = Quaternion.Euler(angleX, 0, 0);
            // 再创建绕 Y 轴旋转 angleY 度的四元数
            Quaternion rotationY = Quaternion.Euler(0, sunAngleY, 0);

            // 先将原始向量绕 X 轴旋转
            Vector3 rotatedAroundX = rotationX * Vector3.forward;
            // 再将绕 X 轴旋转后的向量绕 Y 轴旋转
            Vector3 finalRotatedVector = rotationY * rotatedAroundX;

            // 设置主平行光的方向
            mainDirLight.transform.forward = finalRotatedVector;
        }

       
    }
}